﻿using System.Text;
using Core.Authorization;
using Core.Authorization.Handlers;
using Core.Identity.Common.Auth.Jwt;
using Core.Identity.Common.Interfaces.Common.Interfaces;
using Core.Identity.Tokens;
using Core.Infrastructure;
using Core.Interfaces.Users;
using Core.Persistence;
using Infrastructure.Identity.Tokens;
using Infrastructure.Identity.Users;
using Infrastructure.Mvc.Routing;
using Infrastructure.Persistence;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;

namespace Infrastructure.Startups;

/// <summary>
/// 身份认证
/// </summary>
internal class BoilerplateIdentityStartup : IBoilerplateStartup, IRouteProvider
{
    public int Order => 899;//在加载MVC之前加载

    public int Priority => Order;

    public void Configure(IApplicationBuilder application)
    {
        application.UseAuthentication();
        application.UseAuthorization();
    }

    public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
    {
        #region 服务注册
        //var config = ConfigurationsExtensions.AddJsonFile("identity");
        services.Configure<JwtOptions>(configuration.GetSection(nameof(JwtOptions)));

        services.AddScoped<ICurrentUserService, CurrentUserService>();
        services.AddScoped<ITokenService, TokenService>();
        #endregion

        #region 授权认证
        JwtOptions jwtOptions = configuration.GetSection(nameof(JwtOptions)).Get<JwtOptions>()!;
        services.AddAuthorization();
        services.AddAuthentication(options =>
        {
            options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = nameof(ResponseAuthenticationHandler); //401
            options.DefaultForbidScheme = nameof(ResponseAuthenticationHandler);    //403
        }).AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new()
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = JwtAuthConstants.Issuer,
                ValidAudience = JwtAuthConstants.Audience,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.Key)),
                ClockSkew = TimeSpan.FromSeconds(0)
            };
            options.Events = new JwtBearerEvents
            {
                OnMessageReceived = context =>
                {
                    var accessToken = context.Request.Query["access_token"];
                    // If the request is for our hub...
                    var path = context.HttpContext.Request.Path;
                    if (!string.IsNullOrEmpty(accessToken))
                    {
                        // Read the token out of the query string
                        context.Token = accessToken;
                    }
                    return Task.CompletedTask;
                }
            };
        }).AddScheme<AuthenticationSchemeOptions, ResponseAuthenticationHandler>(nameof(ResponseAuthenticationHandler), o => { });
        #endregion

        #region 数据库上下文
        ArgumentNullException.ThrowIfNull(services);
        services.BindDbContext<IdentityDbContext>();

        services.AddScoped<IIdentityDbContext>(
            provider => provider.GetRequiredService<IdentityDbContext>());

        services.AddScoped<IDbInitializer, IdentityDbInitializer>();
        #endregion
    }

    public void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder)
    {
        endpointRouteBuilder
        .MapControllers()
        .RequireAuthorization();
    }
}
